home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / info-service / gopher / Unix / gateways / techinfo / gophtech / gophtech.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-01  |  24.9 KB  |  1,041 lines

  1. /* 
  2.   Gopher --> TechInfo Gateway
  3.   Copyright November 1992, January 1993 by the University of Pennsylvania.
  4.  
  5.   Export of this software from the United States of America is assumed
  6.   to require a specific license from the United States Government.  It
  7.   is the responsibility of any person or organization contemplating
  8.   export to obtain such a license before exporting.  Within that
  9.   constraint, permission to use, distribute, or copy this software is
  10.   granted, provided that this copyright notice appear on all copies.
  11.   This software is provided as is, with no explicit nor implicit
  12.   warranty.
  13.  
  14. */
  15. /* HISTORY:
  16.  
  17. Mar 1993: version 1.5
  18.       Added recognition of telnet and tn3270 file types (TI_TELNETSESS).
  19.       Fixed bug which caused NeXT gopher to barf -- 
  20.           Changed "\r\n.\r\n" to ".\r\n" at the end of each element sent.
  21.       Commented out various lines which logged extra information.
  22.       Took out the test "University of Pennsylvania" system
  23.           from techinfo-telnet menu.
  24.  
  25. Jan 1993: version 1.4
  26.       Added ability to point at local Sources document
  27.  
  28. Jan 1993: version 1.3 
  29.       Added ability to point at local Gopher server.
  30.       Added TechInfo Source to Path (informational only --
  31.               the gateway ignores it).
  32.       Added Full Text Searching (do #define WAIS or CFLAGS=-DWAIS)
  33.  
  34. Nov 1992: version 1.2 added GIF.
  35. Feb 1992: Created the gateway.
  36.  
  37. */
  38. #include <stdio.h>
  39. #include <strings.h>
  40. #include <errno.h>
  41. #include <sys/types.h>
  42. #include <sys/socket.h>
  43. #include <netinet/in.h>
  44. #include <netdb.h>
  45. #include "gw.h"
  46.  
  47. #define GWVERSION     "GOPH-TIGW:1.5"
  48. #define ABOUT_GW      "Goph-TI-Gateway"   /* About this gopher */
  49. #define TERMBASEDTI   "telnet-techinfo"     /* Telnet session to techinfo */
  50. #define WORLDWIDETI   "worldwide-techinfo"  /* List of all TechInfo servers */
  51. #define SOURCESINFO   "sources "
  52.  
  53. int gophsock = -1;
  54. int gophinsock = -1;
  55.  
  56. char tibuf[200000];
  57. char gophbuf[10000];
  58. char *gatewayhost;
  59. char gatewayport[40];
  60. char remotehost[500];
  61.  
  62. #define CR '\r'
  63. #define LF '\n'
  64. #define EOM             ".\r\n"
  65. #define EOM_LEN         (sizeof(EOM) -1)
  66. #define    terminator(str)    (!strncmp(str, EOM, EOM_LEN))
  67.  
  68. #ifndef RUNTIME_UID
  69. #define RUNTIME_UID 1   /* 1 is usually the DAEMON */
  70. #endif
  71.  
  72. /* TechInfo Protocol */
  73. #define TICMD_GETSERVERS        "m"
  74. #define TICMD_GETMENU           "w:2:%s:1"
  75. #define TICMD_GETDOC            "t:%s:%d:%d"
  76. #define TICMD_KEYSRCH           "b:%s"
  77. #define TICMD_KEYSRCH_NODEID    "b:%s:%s"
  78. #define TICMD_VERSION           "v:%s"
  79. #define TICMD_SHOWFLAGS         "O:2"
  80. #define TIOKAY                  "0:"
  81. #define TIMAXFIELDS             40
  82. #define TIDELIM                 ':'
  83. #define TOTCHARSTR              "Total Characters :"
  84. #define TI_GIFIMAGE              0x40
  85. #define TI_TELNETSESS            0x2000
  86. #define TICMD_FULLTXTSRCH       "J:%s"
  87. #define TICMD_FULLTXTSRCH_NODEID  "J:%s:%s"
  88.  
  89.  
  90.  
  91. /* Gopher Protocol */
  92. #define GO_DOC        '0'
  93. #define GO_MENU        '1'
  94. #define GO_CSO          '2'
  95. #define GO_ERR          '3'
  96. #define GO_MACHQX       '4'
  97. #define GO_DOSBIN       '5'
  98. #define GO_UUENCODED    '6'
  99. #define GO_SEARCH       '7'
  100. #define GO_TELNET       '8'
  101. #define GO_BINARY       '9'
  102. #define GO_GIF          'g'
  103. #define GO_DUPLSERV     '+'
  104. #define GO_TN3270       'T'
  105.  
  106. #define GO_DELIM        '\t'
  107.  
  108. /* Intermediary protocol */
  109. #define I_DELIM         ' '
  110. #define I_DOC           'D'
  111. #define I_MENU          'M'
  112. #define I_KEYSRCH       'K'
  113. #define I_GIFIMAGE      'I'
  114. #define I_FULLTXTSRCH   'F'
  115.  
  116.  
  117. getreq (char *request, int max, int insock)
  118. {
  119.   int idx;
  120.   char *cp;
  121.  
  122.   readline (request, max, insock, &idx);
  123.   cp = index (request, CR);
  124.   if (cp) *cp = 0;
  125.   cp = index (request, LF);
  126.   if (cp) *cp = 0;
  127. }
  128.  
  129.  
  130. write_doc (int gophsock, int readlast, int len, int TextDoc, char *docbuf, 
  131.        int *totalsent)
  132. {
  133.   int wrote;
  134.   int towrite;
  135.   int pos1, pos2;
  136.  
  137.   /*
  138.     if TextDoc is set, then we need to add CR before each LF,
  139.     since the TI server doesn't send CR LF at the end of every line 
  140.     Also, assuming that if TextDoc contains LF . LF, it should
  141.     be changed to CF LF . . CF LF
  142.     
  143.     known problem -- if the TI server breaks up the chunks it
  144.     sends on a line boundary, and sends a period LF, then
  145.     this code will NOT properly quote that period with another one.
  146.     */
  147.   
  148.   if (readlast)         /* if these were the last chars to be read */
  149.     towrite = len - 4;
  150.   else
  151.     towrite = len;
  152.  
  153.   if (TextDoc) {
  154.     pos1 = 0;
  155.     do {
  156.       for (pos2=pos1; docbuf[pos2] != LF && pos2 < towrite-1; 
  157.        pos2++);
  158.  
  159.       if (docbuf[pos2] == LF) {  /* found an End of Line */
  160.     wrote = write (gophsock, docbuf+pos1, pos2-pos1);
  161.     if (wrote < 0)
  162.       ErrExit("Error writing document to gopher");
  163.     *totalsent = *totalsent + wrote;
  164.     write (gophsock, "\r", 1); (*totalsent)++; 
  165.     write (gophsock, "\n", 1); (*totalsent)++;
  166.     
  167.     if (pos2 + 2 < towrite && 
  168.         docbuf[pos2+1] == '.' && docbuf[pos2+2] == LF) {
  169.       write (gophsock, ".", 1);
  170.       (*totalsent)++;
  171.     }
  172.     pos1 = pos2 + 1;
  173.       }
  174.       
  175.       else { /* No more LF left in the buffer */
  176.     wrote = write (gophsock, docbuf+pos1, towrite-pos1);
  177.     if (wrote < 0)
  178.       ErrExit ("Error sending document to gopher");
  179.     (*totalsent) += wrote;
  180.     pos1 = towrite;
  181.       }
  182.       
  183.     } while (pos1 < towrite);
  184.   }
  185.   
  186.   else {  /* Document is not Text, so just send it as it comes from TI */
  187.     wrote = write (gophsock, docbuf, towrite);
  188.     if (wrote < 0)
  189.       ErrExit ("Error sending nontext document to gopher");
  190.     (*totalsent) += wrote;
  191.   }
  192. }
  193.  
  194.  
  195.  
  196.  
  197. int send_ti_doc (int tisock, int gophsock, char *nodeid, int TextDoc)
  198. {
  199.   char docbuf[12200];
  200. #define DOC_BLKSZ (sizeof(docbuf)-200)
  201.   long startat;
  202.   long totalchars;
  203.   long totalsent = 0;
  204.   char *cp;
  205.   int len;
  206.   int toread;
  207.   int red;
  208.  
  209.   startat = 0;
  210.   do {
  211.     sprintf (tibuf, TICMD_GETDOC, nodeid, startat, DOC_BLKSZ);
  212.     /*    sprintf (docbuf, "ToTechinfo:%s", tibuf);
  213.       logdebug (docbuf); */
  214.     send_msg (tisock, tibuf, strlen(tibuf));
  215.     readline (docbuf, DOC_BLKSZ, tisock, &len);
  216.  
  217.     if (startat == 0) {
  218.       totalchars = atoi (docbuf);
  219. /*      sprintf (tibuf, "Document is %d bytes", totalchars);
  220.       logdebug (tibuf); */
  221.     }
  222.  
  223.     cp = strstr (docbuf, TOTCHARSTR);
  224.     if (cp) {
  225.       cp = cp + sizeof(TOTCHARSTR) - 1;
  226.       toread = atoi(cp);
  227.       read (tisock, docbuf, 1);  /* TI server sends 1 extra character (a LF)
  228.                     between 1st line & the document */
  229.  
  230.       do {
  231.     red = read (tisock, docbuf, toread);
  232.     toread = toread - red;
  233.     write_doc (gophsock, toread < 1, red, TextDoc, docbuf, &totalsent);
  234.       } while (toread > 0);
  235.  
  236.       startat = startat + DOC_BLKSZ;
  237.     }
  238.     else {
  239.       sprintf (tibuf, "Unable to find %s in TI server's response %s\n",
  240.           TOTCHARSTR, docbuf);
  241.       ErrExit (tibuf);
  242.     }
  243.  
  244.   } while (totalchars - startat > 0);
  245.  
  246.   sprintf (docbuf, "Sent %d bytes", totalsent);
  247.   logdebug (docbuf);
  248.  
  249.   if (totalsent < 1) {
  250.     sprintf (docbuf, "%s", "File does not exist!!!!!");
  251.     send_msg (gophsock, docbuf, strlen(docbuf));
  252.   }
  253.   return totalsent;
  254. }
  255.  
  256.  
  257.  
  258.  
  259. ErrExit (char * msg)
  260. {
  261.   char *buf;
  262.  
  263.   write (gophsock, "\r\n.\r\n", 5);
  264.  
  265.   buf = (char *) malloc (strlen(msg)+20);
  266.   sprintf (buf, "FatalError:%s", msg);
  267.   logdebug (buf);
  268.   exit(-100);
  269. }
  270.  
  271.  
  272. int parse_fields (char delim, char *line, char *fields[], int maxfields)
  273. {
  274.   char *cp = line;
  275.   int argcnt = 0;
  276.  
  277.   while (argcnt < maxfields) {
  278.     fields[argcnt] = cp;
  279.     argcnt++;
  280.     while (*cp && *cp != delim)
  281.       cp++;
  282.     if (!*cp)
  283.       break;
  284.     *cp = 0;
  285.     cp++;
  286.   }
  287.   fields[argcnt] = (char *) 0;
  288.   return argcnt;
  289. }
  290.  
  291.  
  292. struct hostent *
  293. gethostbyn_or_ad (host)
  294.      char *host;
  295. {
  296.   u_long ip_addrl;
  297.   struct hostent *h;
  298.  
  299.   if (isdigit (host[0])) {     /* if name begins with a digit, assume IP adr */
  300.     ip_addrl = inet_addr (host);
  301.     h = gethostbyaddr (&ip_addrl, sizeof(u_long), AF_INET);
  302.     return (h);
  303.   }
  304.   else {
  305.     h = gethostbyname (host); 
  306.     return (h);
  307.   }
  308. }
  309.  
  310.  
  311. int getportbyn_or_num (str, port)
  312.      int *port;
  313.      char *str;
  314. {
  315.   struct servent *servent;
  316.  
  317.   if ( isdigit(str[0]) ) {   /* if its a number, convert ascii to int */
  318.     *port = atoi(str);
  319.     *port = htons( (u_short) *port);
  320.   }
  321.   else {        /* if not a number, look up name in Ultrix */
  322.     servent = getservbyname (str, "tcp");
  323.     if (servent == NULL)
  324.       return (-1);
  325.     *port = servent->s_port;
  326.   }
  327.   return (1);
  328. }
  329.  
  330.  
  331.  
  332.  
  333.  
  334. int
  335. inet_connect(char *hostname, char *service, char **errstr)
  336. {
  337. #define ERRORMSG_SIZE 200
  338.   struct hostent *host;
  339.   int toport;
  340.   struct sockaddr_in sin;
  341.   int sock;
  342.   extern char *sys_errlist[];
  343.   extern int sys_nerr;
  344.  
  345.   *errstr = (char *) malloc (ERRORMSG_SIZE);
  346.   (*errstr)[0] = 0;
  347.  
  348.   host = gethostbyn_or_ad (hostname);
  349.  
  350.   if (host == NULL) {
  351.     sprintf (*errstr, "%s: Unknown host", hostname);
  352.     return -1;
  353.   }
  354.  
  355.   else  if (getportbyn_or_num (service, &toport) < 0)  {
  356.     sprintf (*errstr, "%s: Unknown TCP service", service);
  357.     return -1;
  358.   }
  359.  
  360.   else {
  361.     sin.sin_family = host->h_addrtype;
  362.     bcopy(host->h_addr,  &(sin.sin_addr), host->h_length);
  363.     sin.sin_port = toport;
  364.  
  365.     sock = socket (AF_INET, SOCK_STREAM, 0, 0);
  366.     if (sock < 0) {
  367.       strcat (*errstr, "socket: ");
  368.      }
  369.  
  370.     else {
  371.       if (connect (sock, &sin, sizeof (sin)) < 0) {
  372.     strcat (*errstr, hostname);
  373.     strcat (*errstr, ":");
  374.     strcat (*errstr, service);
  375.     strcat (*errstr, ":");
  376.     close (sock);
  377.     sock = -1;
  378.       }
  379.     }
  380.   } 
  381.  
  382.   if (errno >= 0 && errno < sys_nerr)  {
  383.     strcat (*errstr, sys_errlist[errno]);
  384.   }
  385.  
  386.   if (sock >= 0)
  387.     free(*errstr);
  388.   return (sock);
  389. }
  390.  
  391. int 
  392. send_msg(sock,str,len) /* BEWARE! this routine writes into str beyond len! */
  393.      int sock;
  394.      char *str;
  395.      int len;
  396. {
  397.   int wrote;
  398.   char msg[100];
  399.  
  400.   if (sock < 0) return 0;
  401.   if (len < 1) return 0;
  402.  
  403.   str[len] = CR;
  404.   str[len+1] = LF;
  405.   wrote = write(sock, str, len+2);
  406.   if (wrote < 1) {
  407.     sprintf (msg, "Unable to write %d chars to sock %d, errno %d",
  408.          len+2, sock, errno);
  409.     ErrExit (msg);
  410.   }
  411.   else
  412.     return 1;
  413. }
  414.  
  415.  
  416. int readline (char *line, int sz, int sock, int *idx)
  417. {
  418.   int rc;
  419.   char msg[100];
  420.  
  421.   *idx = 0;
  422.   line[*idx] = 0;
  423.   do {
  424.     rc = read(sock, line + *idx, 1);
  425.     if (rc < 0) {
  426.       sprintf (msg, "Error reading line from socket %d, errno %d",
  427.            sock, errno);
  428.       ErrExit (msg);
  429.     }
  430.     (*idx)++;
  431.   } while (*idx < sz-1 && line[*idx-1] != LF);
  432.   line[*idx] = 0;
  433. }
  434.  
  435.  
  436. get_msg(sock, buff, buffsize)   /* read message off socket */
  437.      int             sock;
  438.      char           *buff;
  439.      int             buffsize;
  440. {
  441.   int rc, len;
  442.   char errmsg[100];
  443.  
  444.   len = 0;
  445.   bzero (buff, buffsize);
  446.  
  447.   do {
  448.     rc = read(sock, &buff[len], buffsize - len);
  449.     if (rc < 0 ) {
  450.       sprintf (errmsg, "get_msg: unable to read %d chars from sock %d, errno %d", buffsize-len, sock, errno);
  451.       ErrExit(errmsg);
  452.     }
  453.     len = rc + len;
  454.   } while (rc >= 0 && len <= buffsize && !terminator(&buff[len - EOM_LEN]));
  455.  
  456.   if (terminator (&buff[len - EOM_LEN]))
  457.     len -= EOM_LEN;
  458.  
  459.   buff[len] = '\0';
  460.   return (len);
  461. }
  462.  
  463.  
  464.  
  465.  
  466. logdebug (char *string)
  467. {
  468.   FILE *debugfp;
  469.   long now;
  470.  
  471.   debugfp = fopen (DEBUGLOG, "a");
  472.   if (debugfp != NULL) {
  473.     now = time(0);
  474.     fprintf (debugfp, "%d:%s:%s:%s", getpid(),string, remotehost,ctime(&now));
  475.     fclose(debugfp);
  476.   }
  477. }
  478.  
  479. make_menu_line (char *line, char typ, char *title, char ityp,
  480.         char *tiserver, char *tiport, char *nodeid, char *source,
  481.         char *keys, char *filename)
  482. {
  483.   char *portnum;
  484.   char *loginname;
  485.   char *host;
  486.   char *cp;
  487.   
  488.   if (typ == GO_TELNET || typ == GO_TN3270) {
  489.     /* if it's a telnet/tn3270 type of thing, then
  490.        need to change it to gopher style information */
  491.     
  492.     /* From TI server: keys format: <type><space><port>  E.g.: 8 23  */
  493.     cp = index (keys, ' ');
  494.     if (cp) portnum = cp+1;
  495.     else portnum = "0";         /* DEFAULT TELNET PORT ACCORDING TO GOPHER */
  496.  
  497.     /* From TI server, for Telnet or TN3270 objects:
  498.        filename format: <login><space><host>  E.g.: gopher dccs.upenn.edu */
  499.     cp = rindex (filename, ' ');
  500.     if (cp) {
  501.       host = cp+1;
  502.       *cp = 0;
  503.       loginname = filename;
  504.     }
  505.     else {
  506.       host = filename;
  507.       loginname = "";
  508.     }
  509.  
  510.     sprintf (line, "%c%s%c%s%c%s%c%s",
  511.          typ, title, GO_DELIM, loginname, GO_DELIM,
  512.          host, GO_DELIM, portnum);
  513.   }
  514.   else {
  515.     sprintf (line, "%c%s%c%c%c%s%c%s%c%s%c%s%c%s%c%s",
  516.          typ, title, GO_DELIM,
  517.          ityp, I_DELIM, tiserver, I_DELIM, tiport, I_DELIM, nodeid,
  518.          I_DELIM, source,
  519.          GO_DELIM, gatewayhost, GO_DELIM, gatewayport);
  520.   }
  521. }
  522.  
  523.  
  524. static void send_server_line(char *line)
  525. {
  526.   char *fields[TIMAXFIELDS];
  527.   char *nodeid, *server, *port, *title;
  528.   char *Title;
  529.   
  530.   parse_fields (TIDELIM, line, fields, TIMAXFIELDS);
  531.   nodeid = fields[0];
  532.   port = fields[1];
  533.   title = fields[5];
  534.   server = fields[6];
  535.  
  536.   Title = (char *) malloc (strlen(title) +  strlen (" TechInfo") + 1);
  537.   strcpy (Title, title);
  538.   strcat (Title, " TechInfo");
  539.  
  540.   make_menu_line (gophbuf, GO_MENU, Title, I_MENU, server, port, nodeid, "",
  541.           "", "");
  542.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  543. }
  544.  
  545. send_ti_server_list()
  546. {
  547.   char *errstr;
  548.   int length;
  549.   int toread, numlines;
  550.   int tisock;
  551.  
  552.   tisock = inet_connect (TISERVERS_HOST, TISERVERS_PORT, &errstr);
  553.   if (tisock < 0) {
  554.     sprintf(gophbuf, "Couldn't get list of TechInfo servers. %s (port %s)",
  555.         errstr, TISERVERS_PORT);
  556.     ErrExit (gophbuf);
  557.   }
  558.   else {
  559.     init_connect (tisock);
  560.  
  561.     sprintf (tibuf, "%s", TICMD_GETSERVERS);
  562.     /*    sprintf (gophbuf, "ToTechinfo:%s", tibuf);
  563.       logdebug (gophbuf); */
  564.  
  565.     send_msg (tisock, tibuf, strlen(tibuf));
  566.     readline (tibuf, sizeof(tibuf), tisock, &length);
  567.  
  568.     toread = atoi (tibuf);
  569.     numlines = 0;
  570.   
  571.     while (numlines < toread) {
  572.       readline (tibuf, sizeof(tibuf), tisock, &length);
  573.       numlines++;
  574.       send_server_line(tibuf);
  575.     }
  576.     sprintf (gophbuf, "Sent %d server lines", numlines);
  577.     logdebug (gophbuf);
  578.   }
  579. }
  580.  
  581. /*
  582.   Disgusting hack:
  583.   The TI nodetype is NOT entirely in one place in the nodes' info string.
  584.   Telnet session type files may actually be TN3270 things.
  585.   Look in keys to get the scoop.
  586.   */
  587.  
  588. whatis_type (char *flags, char *filename, char *intermedtype, char *gophertype,
  589.          char *keys)
  590. {
  591.   int iflags;
  592.  
  593.   iflags = atoi(flags);
  594.  
  595.   if (iflags & TI_GIFIMAGE) {
  596.     *gophertype = GO_GIF;
  597.     *intermedtype = I_GIFIMAGE;
  598.   }
  599.   else if (iflags & TI_TELNETSESS) {
  600.     /* ASSUMPTION: TI Server uses the Gopher characters to indicate
  601.        whether it's a Telnet or a TN3270 type of file */
  602.     *gophertype = *keys;
  603.     *intermedtype = *gophertype;
  604.   }
  605.  
  606.   else if (strlen(filename) > 0) {
  607.     *gophertype = GO_DOC;
  608.     *intermedtype = I_DOC;
  609.   }
  610.   else {
  611.     *intermedtype = I_MENU;
  612.     *gophertype = GO_MENU;
  613.   }
  614.  
  615. }
  616.  
  617.  
  618.  
  619. static int send_menu_item (char *line, char *tiserver, char *tiport, int minlevel)
  620. {
  621.   char *fields[TIMAXFIELDS];
  622.   char selector[500];
  623.   char *title, *filename, *nodeid, *level, *flags, *source, *keys;
  624.   char ityp, gtyp;
  625.  
  626.   parse_fields (TIDELIM, line, fields, TIMAXFIELDS);
  627.   level = fields[0];
  628.   nodeid = fields[1];
  629.   flags = fields[2];
  630.   keys = fields[4];
  631.   title = fields[5];
  632.   filename = fields[8];
  633.   source = fields[6];
  634.   
  635.   if (atoi(level) < minlevel)
  636.     return 0;
  637.   
  638.   whatis_type (flags, filename, &ityp, >yp, keys);
  639.   make_menu_line (gophbuf, gtyp, title, ityp, tiserver, tiport, nodeid,source,
  640.           keys, filename);
  641.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  642.   return 1;
  643. }
  644.  
  645. send_search_item (char itype, char *tiserver, char *tiport, char *nodeid)
  646. {
  647.   char title [100];
  648.  
  649.   if (strlen (nodeid) > 0) 
  650.     sprintf (title, "%s search the items in this menu", 
  651.          itype == I_KEYSRCH ? "Keyword" : "Full Text");
  652.   else
  653.     sprintf (title, "%s search all nodes at this TechInfo server",
  654.          itype == I_KEYSRCH ? "Keyword" : "Full Text");
  655.  
  656.   sprintf (gophbuf, "%c%s%c%c%c%s%c%s%c%s%c%s%c%s",
  657.        GO_SEARCH, title, GO_DELIM,
  658.        itype, I_DELIM, tiserver,
  659.        I_DELIM, tiport, I_DELIM, nodeid,
  660.        GO_DELIM, gatewayhost, GO_DELIM, gatewayport);
  661.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  662. }
  663.  
  664.  
  665.  
  666.  
  667. send_ti_nodelist (int tisock, char *tiserver, char *tiport, int *sent, int minlevel)
  668. {
  669.   int toread, numlines;
  670.   int length;
  671.  
  672.   readline (tibuf, sizeof(tibuf), tisock, &length);
  673.   toread = atoi (tibuf);
  674.   numlines = 0;
  675.   *sent = 0;
  676.   while (numlines < toread) {
  677.     readline (tibuf, sizeof(tibuf), tisock, &length);
  678.     numlines++;
  679.     *sent += send_menu_item (tibuf, tiserver, tiport, minlevel);
  680.   }
  681.   readline (tibuf, sizeof(tibuf), tisock, &length);
  682. }
  683.  
  684.  
  685. static void send_sources_info (char *srvr)
  686. {
  687.   int tisock;
  688.   char *errstr;
  689.  
  690.   if (*SOURCES_MSGFILE)
  691.     send_message_file (SOURCES_MSGFILE);
  692.  
  693.   if (*LOCAL_SOURCES_NODEID && *LOCALTI_SERVER &&
  694.       strcmp (LOCALTI_SERVER, srvr) == 0) {
  695.  
  696.     /* connect to localti server, retrieve the document associated
  697.        with local sources nodeid, translate it, send it to gopher client */
  698.  
  699.     tisock = inet_connect (LOCALTI_SERVER, LOCALTI_PORT, &errstr);
  700.     if (tisock < 0) {
  701.       sprintf(gophbuf, "Couldn't connect to Techinfo:%s (port %s)",
  702.         errstr, LOCALTI_PORT);
  703.       ErrExit (gophbuf);
  704.     }
  705.     else {
  706.       init_connect (tisock);
  707.       send_ti_doc (tisock, gophsock, LOCAL_SOURCES_NODEID, 1);
  708.     }
  709.   }
  710. }
  711.  
  712.  
  713.  
  714.  
  715. int send_sources_item (char *tiserver)
  716. {
  717.   /* Only offer this item if either 
  718.      1) there's a message file  or
  719.      2) the server is the local one and there's a LOCAL SOURCES NODEID 
  720.      */
  721.  
  722.   if (*SOURCES_MSGFILE || 
  723.       ((strcasecmp(tiserver, LOCALTI_SERVER) == 0) && *LOCAL_SOURCES_NODEID)) {
  724.     sprintf (gophbuf, "%cSources (Providers) of Information\t%s%s\t%s\t%s",
  725.          GO_DOC, SOURCESINFO, tiserver, gatewayhost, gatewayport);
  726.     send_msg (gophsock, gophbuf, strlen(gophbuf));
  727.     return 1;
  728.   }
  729.   else
  730.     return 0;
  731. }
  732.  
  733.  
  734. init_connect (int tisock)  /* call this after successful inet_estab */
  735. {
  736.   get_msg (tisock, tibuf, sizeof(tibuf)); /* get the banner */
  737.   send_version(tisock);
  738.   turnon_tiflags (tisock);
  739. }
  740.  
  741.  
  742.  
  743. static void do_ti_trans(char *request)
  744. {
  745.   char *fields[4];
  746.   int tisock;
  747.   char *tiserver, *tiport, *typ, *nodeid;
  748.   char *errstr;
  749.   char *target = NULL;
  750.   int numitems;
  751.   
  752.   switch (*request) {
  753.   case I_KEYSRCH:
  754.   case I_FULLTXTSRCH:
  755.     /* expect selector-string TAB search-string */
  756.     target = index (request, GO_DELIM);
  757.     if (!target) {
  758.       sprintf (gophbuf, "Didn't understand search request %s", request);
  759.       ErrExit (gophbuf);
  760.       return;
  761.     }
  762.     /* Replace the delimiter with end-of-string marker */
  763.     *target = '\0';
  764.     target++;
  765.     /* fall through to parse_fields intentionally */
  766.  
  767.   case I_DOC:
  768.   case I_MENU:
  769.   case I_GIFIMAGE:
  770.     
  771.     parse_fields (I_DELIM, request, fields, 4);
  772.     typ = fields[0];
  773.     tiserver = fields[1];
  774.     tiport = fields[2];
  775.     nodeid = fields[3];
  776.     break;
  777.     
  778.   default:
  779.     sprintf (gophbuf, "Didn't understand file type %c", *request);
  780.     ErrExit (gophbuf);
  781.     return;
  782.   }
  783.  
  784. /* okay, we've parsed the Intermed. token... */
  785.  
  786.  
  787. /*  printf ("serv=%s, port=%s, nodeid=%s, target=%s.\n",
  788.       tiserver, tiport, nodeid, target); */
  789.  
  790.   tisock = inet_connect (tiserver, tiport, &errstr);
  791.   if (tisock < 0) {
  792.     sprintf(gophbuf, "Couldn't connect to Techinfo:%s (port %s)",
  793.         errstr, tiport);
  794.     ErrExit (gophbuf);
  795.   }
  796.   else {
  797.     init_connect (tisock);
  798.  
  799.     switch (*typ) {
  800.     case I_KEYSRCH:
  801.     case I_FULLTXTSRCH:
  802.       if (strlen(nodeid) > 0) {
  803.     if (*typ == I_KEYSRCH)
  804.       sprintf (tibuf, TICMD_KEYSRCH_NODEID, target, nodeid);
  805.     else 
  806.       sprintf (tibuf, TICMD_FULLTXTSRCH_NODEID, target, nodeid);
  807.       }
  808.       else {
  809.     if (*typ == I_KEYSRCH)
  810.       sprintf (tibuf, TICMD_KEYSRCH, target);
  811.     else
  812.       sprintf (tibuf, TICMD_FULLTXTSRCH, target);
  813.       }
  814.  
  815.       /*      sprintf (gophbuf, "ToTechinfo:%s", tibuf);
  816.           logdebug (gophbuf); */
  817.  
  818.       send_msg (tisock, tibuf, strlen(tibuf));
  819.       send_ti_nodelist(tisock, tiserver, tiport, &numitems, 0);
  820.       sprintf (tibuf, "Sent %d items", numitems);
  821.       logdebug (tibuf);
  822.       break;
  823.  
  824.     case I_DOC:
  825.     case I_GIFIMAGE:
  826.       send_ti_doc (tisock, gophsock, nodeid, *typ != I_GIFIMAGE);
  827.       break;
  828.  
  829.     case I_MENU:
  830.       sprintf (tibuf, TICMD_GETMENU, nodeid);
  831.       /*      sprintf (gophbuf, "ToTechinfo:%s", tibuf);
  832.           logdebug (gophbuf); */
  833.       send_msg (tisock, tibuf, strlen(tibuf));
  834.  
  835.       send_ti_nodelist (tisock, tiserver, tiport, &numitems, 1);
  836.       send_search_item (I_KEYSRCH, tiserver, tiport, "");
  837.       send_search_item (I_KEYSRCH, tiserver, tiport, nodeid);
  838.       numitems = numitems + 2;
  839.  
  840. #ifdef WAIS
  841.       send_search_item (I_FULLTXTSRCH, tiserver, tiport, "");
  842.       send_search_item (I_FULLTXTSRCH, tiserver, tiport, nodeid);
  843.       numitems = numitems + 2;
  844. #endif
  845.       if (send_sources_item (tiserver))
  846.     numitems = numitems + 1;
  847.       sprintf (tibuf, "Sent %d items", numitems);
  848.  
  849.       logdebug (tibuf);
  850.       break;
  851.     }
  852.   }
  853. }
  854.  
  855. terminalbased_ti()
  856. {
  857.   sprintf (gophbuf, "%cMassachusetts Institute of Technology%c%ctechinfo.mit.edu%c0",
  858.        GO_TELNET, GO_DELIM, GO_DELIM,GO_DELIM);
  859.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  860.  
  861.   sprintf (gophbuf, "%cUniversity of Pennsylvania%c%cpenninfo.upenn.edu%c0",
  862.        GO_TELNET, GO_DELIM, GO_DELIM,GO_DELIM);
  863.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  864.  
  865.   sprintf (gophbuf, "%cMississippi State%cMSUINFO%cmsuinfo.msstate.edu%c0",
  866.        GO_TELNET, GO_DELIM, GO_DELIM,GO_DELIM);
  867.   send_msg (gophsock, gophbuf, strlen(gophbuf));
  868.  
  869. }
  870.  
  871.  
  872.  
  873.  
  874. send_message_file (char *filename)
  875. {
  876.   FILE *fp;
  877.   char line[100], *cp;
  878.  
  879.   fp = fopen (filename, "r");
  880.   if (fp == NULL) {
  881.     sprintf (gophbuf, "Unable to read msg file %s", filename);
  882.     ErrExit (gophbuf);
  883.   }
  884.  
  885.   do {
  886.     if (fgets (line,sizeof(line)-1,fp) == NULL)
  887.       break;
  888.     else {
  889.       cp = index (line, '\n');
  890.       if (cp) {
  891.     write (gophsock, line, cp-line);
  892.     write (gophsock, "\r\n", 2);
  893.       }
  894.       else
  895.     write (gophsock, line, strlen(line));
  896.     }
  897.   } while (1);
  898. }
  899.  
  900.  
  901.  
  902. do_about_gw()
  903. {
  904.   send_message_file (MSGFILE);
  905. }
  906.  
  907.  
  908.  
  909. send_version(int tisock)
  910. {
  911.   sprintf (tibuf, TICMD_VERSION, GWVERSION);
  912.   send_msg (tisock, tibuf, strlen(tibuf));
  913.   get_msg(tisock, gophbuf, sizeof(gophbuf));
  914. }
  915.  
  916.  
  917. turnon_tiflags (int tisock)
  918. {
  919.   sprintf (tibuf, TICMD_SHOWFLAGS);
  920.   send_msg (tisock, tibuf, strlen(tibuf));
  921.   get_msg (tisock, gophbuf, sizeof(gophbuf));
  922. }
  923.  
  924. set_remote_hostname ()
  925. {
  926.   struct sockaddr_in sname;
  927.   struct hostent *host;
  928.   int namelen;
  929.  
  930.   namelen = sizeof(sname);
  931.  
  932.   if (getpeername (gophinsock, &sname, &namelen)) {
  933.     if (errno == ENOTSOCK) 
  934.       sprintf (remotehost, "STDIN");
  935.     else
  936.       sprintf (remotehost, "getpeername-errno-%d", errno);
  937.   }
  938.  
  939.   else {
  940.     host = gethostbyaddr(&sname.sin_addr, sizeof(sname.sin_addr), AF_INET);
  941.     if (!host)
  942.       sprintf (remotehost, "gethostbyaddr-errno-%d", errno);
  943.     else
  944.       sprintf (remotehost, "%s", host->h_name);
  945.   }
  946. }
  947.  
  948. main (int argc, char *argv[])
  949. {
  950.   char request[1000];
  951.   char *ptr;
  952.   int port;
  953.   
  954.   setreuid (RUNTIME_UID, RUNTIME_UID);
  955.   if (getuid() == 0 || geteuid() == 0) {
  956.     fprintf (stderr, "\r\n.\r\n");
  957.     /* should send a message to syslog daemon */
  958.     exit (-1);
  959.   }
  960.   
  961.   gophsock =  fileno(stdout);
  962.   gophinsock = fileno(stdin);
  963.   set_remote_hostname ();
  964.   
  965. /*  logdebug ("Start"); */
  966.   
  967.   if (argc < 3) {
  968.     sprintf (gophbuf, "Usage: %s <hostname> <port>", argv[0]);
  969.     ErrExit(gophbuf);
  970.   }
  971.   gatewayhost = argv[1];
  972.   if (getportbyn_or_num (argv[2], &port) < 0) {
  973.     sprintf (gophbuf, "Unknown service port argv2: %s", argv[2]);
  974.     ErrExit (gophbuf);
  975.   }
  976.   port = ntohs(port);
  977.   sprintf (gatewayport, "%d", port);
  978.   
  979.   getreq (request, sizeof(request), gophinsock);
  980.   sprintf (gophbuf, "Request:%s", request);
  981.   logdebug (gophbuf);
  982.   
  983.   for (ptr = request; *ptr && isspace(*ptr) ; ptr++);
  984.   if (*ptr == 0) {                 /* is it a blank line? */
  985.     sprintf (gophbuf, "%cAbout this Internet Gopher%c%s%c%s%c%s",
  986.          GO_DOC, GO_DELIM, ABOUT_GW, GO_DELIM,
  987.          gatewayhost, GO_DELIM, gatewayport);
  988.     send_msg (gophsock, gophbuf, strlen(gophbuf));
  989.     
  990.     if (strlen(LOCALTI_SERVER) > 0) {
  991.       sprintf (request, "%c%c%s%c%s%c%s",
  992.            I_MENU, I_DELIM,  LOCALTI_SERVER, I_DELIM, LOCALTI_PORT, I_DELIM, 
  993.            LOCALTI_MAINMENU);
  994.       do_ti_trans(request);
  995.     }
  996.  
  997.     sprintf (gophbuf, "%cWorld Wide TechInfo%c%s%c%s%c%s",
  998.          GO_MENU, GO_DELIM, WORLDWIDETI, GO_DELIM,
  999.          gatewayhost, GO_DELIM, gatewayport);
  1000.     send_msg (gophsock, gophbuf, strlen(gophbuf));
  1001.     
  1002.     if (strlen(LOCALGOPHTITLE) > 0) {
  1003.       sprintf (gophbuf, "%c%s%c%s%c%s%c%s",
  1004.            GO_MENU, LOCALGOPHTITLE, GO_DELIM, LOCALGOPHERPATH, GO_DELIM,
  1005.            LOCALGOPHERSERVER, GO_DELIM, LOCALGOPHERPORT);
  1006.       send_msg (gophsock, gophbuf, strlen(gophbuf));
  1007.     }
  1008.     
  1009.     sprintf (gophbuf, "%cWorld Wide Gopher%c1/Other Gopher and Information Servers%cgopher.tc.umn.edu%c70",
  1010.          GO_MENU, GO_DELIM, GO_DELIM,GO_DELIM);
  1011.     send_msg (gophsock, gophbuf, strlen(gophbuf));
  1012.   }
  1013.   
  1014.   else if (!strcmp(request, WORLDWIDETI)) {
  1015.     send_ti_server_list();
  1016.     sprintf (gophbuf, "%cTerminal-based TechInfo services%c%s%c%s%c%s",
  1017.          GO_MENU, GO_DELIM, TERMBASEDTI, GO_DELIM,
  1018.          gatewayhost, GO_DELIM, gatewayport);
  1019.     send_msg (gophsock, gophbuf, strlen(gophbuf));
  1020.   }
  1021.   
  1022.   else if (!strcmp(request, ABOUT_GW))
  1023.     do_about_gw();
  1024.  
  1025.   else if (!strncmp(request, SOURCESINFO, strlen(SOURCESINFO)))
  1026.     send_sources_info(request + strlen(SOURCESINFO));
  1027.   
  1028.   else if (!strcmp(request, TERMBASEDTI))
  1029.     terminalbased_ti();
  1030.   
  1031.   else                            /* should be a techinfo menu request */
  1032.     do_ti_trans(request);
  1033.   
  1034.   /* this is the normal exit */
  1035. /*  write (gophsock, "\r\n.\r\n", 5); */
  1036.   write (gophsock, ".\r\n", 3);
  1037. /*  logdebug ("End"); */
  1038.   exit (0);
  1039. }
  1040.  
  1041.